package com.sport.utils.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

@Component
@Slf4j
public class BaseUtils {

    public static <T,R> R copyProperties(T source, Class<R> targetClass) {
        if (source == null || targetClass == null) return null;

        try {
            Class sourceClass = source.getClass();
            R targetReturns = targetClass.newInstance();

            Field[] targetFields = targetClass.getDeclaredFields();
            for (Field singleField : targetFields) {
                if(Modifier.isFinal(singleField.getModifiers())) continue;
                String fieldSuffix = InnerTools.toUpperFirstWord(singleField.getName());

                Field sourceField = null;
                try {
                    sourceField = sourceClass.getDeclaredField(singleField.getName());
                } catch (Exception e) {
                    continue;
                }

                Method targetMethod = null;
                if(sourceField.getType() == singleField.getType())
                    targetMethod = targetClass.getDeclaredMethod("set" + fieldSuffix, singleField.getType());
                else
                    targetMethod = targetClass.getDeclaredMethod("set" + fieldSuffix, sourceField.getType());
                Method sourceMethod = sourceClass.getMethod("get" + fieldSuffix);

                targetMethod.invoke(targetReturns, sourceMethod.invoke(source));
            }

            return targetReturns;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException("服务器内部出错");
        }
    }

    public static <T, R> List<R> copyPropertiesList(List<T> source, Class<R> target) {
        if (source == null || target == null)
            return null;

        ArrayList<R> copyList = new ArrayList<>();
        for (int single = 0; single < source.size(); ++single)
            copyList.add(copyProperties(source.get(single), target));

        return copyList;
    }

    /**
     * Map转换对象器
     * @param targetMap
     * @param target
     * @param <T>
     * @return
     */
    public static <T> T mapToObjectConverter (@NotNull Map targetMap, @NotNull Class<T> target) {
        try {
            if(targetMap == null) return null;

            T returnObject = target.newInstance();

            Field[] fields = target.getDeclaredFields();
            for (Field field : fields) {
                if(Modifier.isFinal(field.getModifiers())) continue;
                String fieldName = field.getName();
                Class fieldType = field.getType();

                Method getFieldMethod = target.getMethod("set" + InnerTools.toUpperFirstWord(fieldName), fieldType);

                Object targetFieldValue = targetMap.get(fieldName);

                getFieldMethod.invoke(returnObject
                        , targetFieldValue.getClass().equals(fieldType)?targetFieldValue:InnerTools.typeMatchFieldConverter(targetFieldValue, fieldType)
                );
            }

            return returnObject;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException( "系统内部出错！Map转换对象器宕机！");
        }
    }

    public static Map<String, Object> secondMapPutIntoFirstMap(Map<String, Object> firstMap, Map<String, Object> secondMap) {
        if (firstMap.size() == 0 || firstMap == null || secondMap.size() == 0 || secondMap == null) return null;

        secondMap.forEach((key, value)->{
            firstMap.put(key, value);
        });

        return firstMap;
    }

    public static Map<String, Object> quickCreateMap(String key, Object value) {
        HashMap<String, Object> objectHashMap = new HashMap<>();
        objectHashMap.put(key, value);
        return objectHashMap;
    }

    public static <T> List<T> findListsDifferentElement (List<T> source, List<T> target) {

        if (target == null) return null;

        List<T> returnsRecord = new ArrayList<>();

        target.forEach((value)->{
            int pos = 0;
            for (int single = 0; single < source.size(); ++single)
                if (value.equals(source.get(single))) {
                    pos = 1;
                    break;
                }

            if (pos == 0) returnsRecord.add(value);
        });

        return returnsRecord.size() == 0 ? null : returnsRecord;
    }

    private static class InnerTools {
        public static String toUpperFirstWord(String target) {
            return target.substring(0,1).toUpperCase().concat(target.substring(1));
        }

        public static <T> Object typeMatchFieldConverter(T target, Class swagTargetType) {
            String value = String.valueOf(target);

            if (swagTargetType.equals(Long.class))
                return Long.valueOf(value);
            else if(swagTargetType.equals(Integer.class))
                return Integer.valueOf(value);
            else return target;
        }

    }
}
